#ifndef _BIO_CPP_PARSECLUSTAL_H
#define _BIO_CPP_PARSECLUSTAL_H
#include <iostream>
#include <string>
#include <vector>
#include <assert.h>
#include <boost/regex.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/foreach.hpp>
#include <boost/algorithm/string.hpp>
#include "bcpp_parse_error.h"

/*
	Example:

	struct TSequenceData
	{
		list<string>	sequence;
		list<string>	acc_line;
		unsigned		count_seq;
		unsigned		count_invalid;
		bool operator()(const string& accession, const string& sequence, unsigned linecnt);
		bool operator()(const string& accession, const std::vector<std::string>& sequence,
																sequence, unsigned linecnt);
		bool operator()(const string& accession, const string& sequence,
						unsigned acc_filepos, unsigned seq_filepos);
						
	};

	bool process_sequence::operator()(	const string& accession,
										const string& sequence, unsigned line_cnt)
	{
		// reject sequences with a null accession code
		if (acc_line == "SP|000")
		{
			++count_invalid;
			cerr << "Invalid sequence on line "  << line_cnt << std::endl;
			return false;
		}

		++count_seq;
		if (!(count_seq % 100))
			cerr << ".";
		sequence.insert(sequence);
		acc_line.insert(accession);
		return true;
	}

	bool process_sequence::operator()(	const string& accession,
										const string& sequence,
										unsigned acc_filepos,
										unsigned seq_filepos)
	{
		// reject sequences with a null accession code
		if (acc_line == "SP|000")
		{
			++count_invalid;
			cerr	<< "Invalid sequence accession and sequence starting at line: ["
					<< line_cnt << "]"	<< std::endl;
			return false;
		}

		++count_seq;
		if (!(count_seq % 100))
			cerr << ".";
		sequence.insert(sequence);
		acc_line.insert(accession);
		return true;
	}

	bool process_sequence::operator()(	const std::string&				accession,
										const std::vector<std::string>&	sequence,
										unsigned						line_cnt)
	{
		// reject sequences with a null accession code
		if (acc_line == "SP|000")
		{
			++count_invalid;
			cerr	<< "Invalid sequence accession and sequence starting at line: ["
					<< line_cnt << "]"	<< std::endl;
			return false;
		}

		++count_seq;
		if (!(count_seq % 100))
			cerr << ".";
		for (unsigned i = 0; i < sequences.size(); ++i)
			sequence += sequences[i];
		acc_line.insert(accession);
		return true;
	}


	void FooBar_blah_de_blah()
	{
		TSequenceData seq_data;
		Process_FA_Sequences(cin, seq_data);
		Process_FA_Sequences_tellg(cin, seq_data);
		Process_FA_Sequences_vec(cin, seq_data);
	}
*/
namespace BioCPP
{


//******************************************************************************

//	Process_FA_Sequences

//		reads each sequence and calculates running totals for statistics
//
//******************************************************************************
template <class Ty_>
void Process_Clustal_Sequences(std::istream& istrm,
                               std::vector<std::string>& preamble,
                               const std::string& format_header,
                               unsigned line_cnt, Ty_& process_sequence)
{
    boost::regex format_regex("^CLUSTAL", boost::regex::icase);
    if (!boost::regex_search(format_header, format_regex, boost::match_default))
    {
        bcpp_parse_format_error error;
        error.set_data(preamble, format_header, line_cnt);
        throw error;
    }

    using boost::algorithm::split; 
	using boost::algorithm::trim_left; 
    using boost::algorithm::is_any_of; 

	// get each line in the CLUSTAL file
	std::string line;
	while (std::getline(istrm, line))
	{
		++line_cnt;

		trim_left(line);
		if (!line.length())
			continue;
        std::vector< std::string > data;
        split( data, line, is_any_of(" \t"), boost::algorithm::token_compress_on );
		//std::cerr << line << ";" << data.size() << "\n";

        // ignore all white space
        if (!data.size())
            continue;

        if (data.size() == 1)
        {
            std::string empty_sequence;
            if (!process_sequence(data[0], empty_sequence, line_cnt))
                return;
        }
        else
            if (!process_sequence(data[0], data[1], line_cnt))
                return;
	}

	return;
}



}

#endif
